/****
 * AOC starter
 * Copyright (c) 2010, 02nz
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Latest version aviliable through the world-wide-web at the following url:
 * http://code.google.com/p/aoc-starter/
 ****/

#include <windows.h>
#include "ui.h"
#include "ui_menu.h"
#include "aoc.h"
#include "resource.h"

PCWSTR SECTION = 0;

static
	CUI *_ui = 0;

extern
	PCWSTR gConfig,
		gPath;

static
LRESULT CALLBACK Proc_Dialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	return _ui->OnMessage(hWnd, uMsg, wParam, lParam);
}

LRESULT CUI::OnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg) 
	{
	case WM_EXITMENULOOP:
		_MenuLoop = 0;
		break;

	case WM_ENTERMENULOOP:
		_MenuLoop = 1;
		break;

	case WM_TRAY:
		switch(LOWORD(lParam))
		{
		case WM_LBUTTONUP:
		case WM_RBUTTONUP:
			Menu_Track();
			break;

		case WM_MOUSEMOVE:
			break;
		}
		break;
	}

	if(_MenuLoop)
		gMenu.OnMessage(hWnd, uMsg, wParam, lParam);

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

CUI::~CUI()
{
	Tray_Hide();
	ExitProcess(0);
}

CUI::CUI()
	:	_ClassName(0)
	,	_hWnd(0)
	,	_MenuLoop(0)
	,	_Menu(0)
{
	_ui = this;
	ZeroMemory(&_TrayIcon, sizeof _TrayIcon);

	_Instance = GetModuleHandle(0);
	_ClassName = L"AOC_LDR";

	if(!CheckConfig())
		CheckPath();

	WNDCLASS WndClass;
	ZeroMemory(&WndClass, sizeof WndClass);

	WndClass.lpfnWndProc = Proc_Dialog;
	WndClass.hInstance = _Instance;
	WndClass.lpszClassName = _ClassName;

	if(!RegisterClass(&WndClass))
		FatalAppExitA(0, "Unable to register class");

	_hWnd = CreateWindowEx(
				WS_EX_CONTROLPARENT|WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE|WS_EX_NOACTIVATE|WS_EX_NOINHERITLAYOUT,
				_ClassName,
				L"AOC_LDR",
				WS_POPUP,
				0,
				0,
				1,
				1,
				NULL,
				NULL,
				_Instance,
				NULL);

	if(!_hWnd)
		FatalAppExitA(0, "Unable to create main window");

	ShowWindow(_hWnd, 0);

	Menu_Init();
	Tray_Init();

	MSG Msg;
	BOOL c;

	while((c = GetMessage(&Msg, NULL, 0, 0)))
	{
		if(c == -1)
			continue;

		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
}

void CUI::Tray_Init()
{
	bool bTSW = (*SECTION == 'a' || *SECTION == 'A') ? 0 : 1; // imba!

	_TrayIcon.cbSize = sizeof(_TrayIcon);
	_TrayIcon.uVersion = NOTIFYICON_VERSION;
	_TrayIcon.hIcon = LoadIcon(_Instance, MAKEINTRESOURCE(bTSW ? IDI_TSW : IDI_MAIN));
	_TrayIcon.hWnd = _hWnd;
	_TrayIcon.uCallbackMessage = WM_TRAY;
	_TrayIcon.uFlags = NIF_ICON | NIF_MESSAGE;
	_TrayIcon.dwInfoFlags = NIIF_NOSOUND;

	Tray_Show();
}

void CUI::Tray_Show()
{
	if(_TrayIcon.hIcon)
		Shell_NotifyIcon(NIM_ADD, &_TrayIcon);
}

void CUI::Tray_Hide()
{
	if(_TrayIcon.hIcon)
		Shell_NotifyIcon(NIM_DELETE, &_TrayIcon);
}

//----------------------------------------------------------

__declspec(noinline)
BOOL CUI::CheckConfig()
{
	WCHAR Path[300];

	GetPrivateProfileString(L"game", L"name", L"AOC", Path, 300, gConfig);
	SECTION = _lstrdup(Path);

	Path[0] = 0;

	if(GetFileAttributes(gConfig) == ~0)
	{
		WritePrivateProfileString(L"game", L"name", SECTION, gConfig);
		WritePrivateProfileString(SECTION, L"args", L"-novideo", gConfig);
		WritePrivateProfileString(SECTION, L"PlaySoundOnce", L"1", gConfig);
		WritePrivateProfileString(SECTION, L"BreakOnError", L"1", gConfig);
		WritePrivateProfileString(SECTION, L"MinigameSound", L"", gConfig);
	}
	else
		GetPrivateProfileString(SECTION, L"path", 0, Path, 300, gConfig);

	return (Path[0] && GetFileAttributes(Path) != ~0);
}

VOID CUI::CheckPath()
{
	WCHAR Path[MAX_PATH];
	Path[0] = 0;

	CheckConfig();

	OPENFILENAME ofn;
	ZeroMemory(&ofn, sizeof ofn);
	ofn.lStructSize	= sizeof ofn;
	ofn.hwndOwner = _hWnd;
	ofn.hInstance = _Instance;
	ofn.nFilterIndex = 1;
	ofn.lpstrFile = Path;
	ofn.nMaxFile = MAX_PATH;
	ofn.lpstrFilter = L"AgeOfConan/TheSecretWorld\0AgeOfConan.exe;AgeOfConanDX10.exe;TheSecretWorld.exe;TheSecretWorldDX10.exe\0All Files\0*.*\0\0";
	ofn.lpstrTitle = L"Show me teh game";
	ofn.Flags = OFN_FILEMUSTEXIST;

	Tray_Hide();

	if(GetOpenFileName(&ofn) && GetFileAttributes(Path) != ~0)
		WritePrivateProfileString(SECTION, L"path", Path, gConfig);

	Tray_Show();
}

//----------------------------------------------------------

VOID NTAPI thr(PCWSTR Path)
{
	Sleep(5000);
	ShellExecute(0, L"open", Path, 0, 0, SW_SHOW);
	delete [] Path;
	ExitThread(0);
}

VOID CUI::Menu_0()
{
	WCHAR Path[300];
	WCHAR Args[300];
	WCHAR Rgn[32];
	WCHAR Sound[300];

	GetPrivateProfileString(SECTION, L"region", L"en", Rgn, 32, gConfig);

	if(!GetPrivateProfileString(SECTION, L"path", 0, Path, 300, gConfig) ||
		GetFileAttributes(Path) == ~0 )
	{
		MessageBoxA(0, "Unable to find game path!", 0, MB_ICONEXCLAMATION);
		return;
	}

	GetPrivateProfileString(SECTION, L"args", L"-novideo", Args, 300, gConfig);

	LONG NameLen = GetPrivateProfileString(SECTION, L"MinigameSound", 0, Sound, 300, gConfig);
	if(NameLen > 3)
	{
		if(Sound[1] != ':') // !x:/, [Sound] -> [...][Sound] -> [gPath][Sound]
		{
			LONG PathLen = lstrlen(gPath);
			for(PWSTR a = Sound, b = &Sound[PathLen]; NameLen >= 0; NameLen--)
				*b++ = *a++;
			memcpy(Sound, gPath, PathLen << 1);
		}
	}
	else
		Sound[0] = 0;

	bool bTSW = (*SECTION == 'a' || *SECTION == 'A') ? 0 : 1; // imba!

	CHAR rgn[] =
	{
		(Rgn[0] | 0x20),
		(Rgn[1] | 0x20),
		0
	};
	PWSTR Err = Run(Path, Args, rgn, Sound,
		GetPrivateProfileInt(SECTION, L"PlaySoundOnce", 1, gConfig),
		GetPrivateProfileInt(SECTION, L"BreakOnError", 1, gConfig),
		bTSW );

	if(!Err &&
		GetPrivateProfileString(L"run", L"path", 0, Path, 300, gConfig) && 
		GetFileAttributes(Path) != ~0 )
	{
		CloseHandle(CreateThread(0, 0x10000, (LPTHREAD_START_ROUTINE)thr, _lstrdup(Path), 0, 0));
	}

	if(Err)
	{
		SetForegroundWindow(_hWnd);
		MessageBox(_hWnd, Err, 0, MB_ICONERROR);
		SAFE_DELETE_ARRAY(Err);
	}
}

PWSTR CUI::GetPath(PWSTR Path, PWSTR Dir)
{
	if(!GetPrivateProfileString(SECTION, L"path", 0, Path, MAX_PATH, gConfig) ||
		GetFileAttributes(Path) == ~0 )
	{
		MessageBoxA(0, "Unable to find game path!", 0, MB_ICONEXCLAMATION);
		return NULL;
	}

	if(!Dir)
		return Path;

	PWSTR e = &Dir[ lstrlen(Path) ];

	if(Dir != Path)
		memcpy(Dir, Path, (PUCHAR)e - (PUCHAR)Dir);

	while(e >= Dir && *e != '\\' && *e != '/')
		--e;
	e[1] = 0;

	return &Path[ &e[1]-Dir ];
}

VOID CUI::Menu_1()
{
	WCHAR Dir[MAX_PATH];
	WCHAR Path[MAX_PATH];

	PWSTR p = GetPath(Path, Dir);
	if(!p)
		return;

	lstrcpy(p, L"ConanPatcher.exe");

	if(GetFileAttributes(Path) != ~0)
	{
		ShellExecute(0, L"open", Path, 0, Dir, SW_SHOW);
		return;
	}

	lstrcpy(p, L"ClientPatcher.exe");

	if(GetFileAttributes(Path) != ~0)
	{
		ShellExecute(0, L"open", Path, 0, Dir, SW_SHOW);
		return;
	}
}

VOID CUI::Menu_2()
{
	WCHAR Path[MAX_PATH];

	PWSTR p = GetPath(Path, Path);
	if(!p)
		return;

	ShellExecute(0, L"open", Path, 0, 0, SW_SHOW);
}

VOID CUI::Menu_3()
{
	CheckPath();
}

VOID CUI::Menu_4()
{
	ShellExecute(0, L"edit", gConfig, 0, gPath, SW_SHOW);
}

VOID CUI::Menu_5()
{
	delete this;
}

struct
{
	PCWSTR s;
	ULONG i;
}
_Regions[] =
{
	{L"en", IDI_GB},
	{L"ru", IDI_RF},
};
#define REGIONS ARRAY_COUNT(_Regions)

VOID CUI::Menu_Init()
{
	_RegionMenu = gMenu.Create();
	_Menu = gMenu.Create();

#define L_ICON(i) LoadIcon(_Instance, MAKEINTRESOURCE(i))

	for(ULONG i = 0; i < REGIONS; i++)
	{
		WCHAR tmp[16];
		for(ULONG j = 0; j < 3; j++)
			tmp[j] = _Regions[i].s[j] ? (_Regions[i].s[j] & ~0x20) : 0;

		_RegionMenu->Append(MF_STRING, MENU_REGION+i, tmp, L_ICON(_Regions[i].i));
	}

	bool bTSW = (*SECTION == 'a' || *SECTION == 'A') ? 0 : 1; // imba!

	_Menu->Append(MF_STRING, MENU_START+0, L"Start game", L_ICON(bTSW ? IDI_TSW : IDI_START));
	_Menu->Append(MF_STRING,	 MENU_START+1, L"Start patcher", L_ICON(IDI_PATCH));
	_Menu->Append(MF_SEPARATOR);
	if(!bTSW)
	{
	_Menu->Append(MF_STRING|MF_POPUP, (UINT_PTR)_RegionMenu->_Menu, L"Region", L_ICON(IDI_RGN));
	_Menu->Append(MF_SEPARATOR);
	}
	_Menu->Append(MF_STRING,	 MENU_START+2, L"Open game path", L_ICON(IDI_DIR));
	_Menu->Append(MF_STRING,	 MENU_START+3, L"Set game path", L_ICON(IDI_PATH));
	_Menu->Append(MF_STRING,	 MENU_START+4, L"Open config", L_ICON(IDI_EDIT));
	_Menu->Append(MF_SEPARATOR);
	_Menu->Append(MF_STRING, MENU_START+5, L"Exit", L_ICON(IDI_EXIT));

	_Menu->SetDefault(MENU_START+0);
}

VOID CUI::Menu_Handle(BOOL Msg)
{
	switch(Msg) 
	{
	case MENU_START+0: Menu_0(); break;
	case MENU_START+1: Menu_1(); break;
	case MENU_START+2: Menu_2(); break;
	case MENU_START+3: Menu_3(); break;
	case MENU_START+4: Menu_4(); break;
	case MENU_START+5: Menu_5(); break;
	}

	if(Msg >= MENU_REGION)
	{
		LONG id = Msg - MENU_REGION;
		if(id < REGIONS)
			WritePrivateProfileString(SECTION, L"region", _Regions[id].s, gConfig);
	}
}

VOID CUI::Menu_Track()
{
	_Menu->Enable(MENU_START+3, 	(GetFileAttributes(gConfig) != ~0));

	WCHAR Path[300];
	WCHAR Rgn[32];

	GetPrivateProfileString(SECTION, L"region", L"eu", Rgn, 32, gConfig);

	if(	!GetPrivateProfileString(SECTION, L"path", 0, Path, 300, gConfig) ||
		GetFileAttributes(Path) == ~0 )
	{
		_Menu->Enable(MENU_START+0, 0);
		_Menu->Enable(MENU_START+1, 0);
		_Menu->Enable(MENU_START+2, 0);
	}
	else
	{
		_Menu->Enable(MENU_START+0, 1);
		_Menu->Enable(MENU_START+1, 1);
		_Menu->Enable(MENU_START+2, 1);
	}

	_RegionMenu->SetDefault(0);

	for(ULONG i = 0; i < REGIONS; i++)
	{
		bool Chk = !lstrcmpi(Rgn, _Regions[i].s);

		if(Chk)
			_RegionMenu->SetDefault(MENU_REGION+i);

		_RegionMenu->Check(MENU_REGION+i, Chk);
	}

	POINT Point;
	GetCursorPos(&Point);

	BOOL Ok = _Menu->Track(
				Point.x,
				Point.y,
				_hWnd,
				TPM_RIGHTBUTTON|TPM_RETURNCMD);

	Menu_Handle(Ok);
}

